package com.pap.uua.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.pap.base.constant.JWTConstants;
import com.pap.base.dto.jwt.JWTTokenDTO;
import com.pap.base.dto.jwt.JWTUserDTO;
import com.pap.base.util.bean.BeanCopyUtilss;
import com.pap.base.util.jwt.JWTTokenUtilss;
import com.pap.base.util.string.StringUtilss;
import com.pap.obj.vo.response.ResponseVO;
import com.pap.rbacfeignapi.IUserService;
import com.pap.rbacfeignapi.dto.UserInfoDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@ResponseBody
public class LoginController {

    private static Logger logger  =  LoggerFactory.getLogger(LoginController.class);

    @Autowired
    private IUserService userService;

    /**
     * 根据类型判断是哪种登录方式，登录获取 JWT
     * @param papToken
     * @param papVersion
     * @param userDTO
     * @return
     */
    @RequestMapping(value = "/token", method = {RequestMethod.POST} )
    // @SentinelResource(value = "token", blockHandler = "handleTokenException", fallback = "handleTokenFallback")
    public ResponseVO<JWTTokenDTO> token(@RequestHeader(value = "papToken", defaultValue = "-1") String papToken,
                                         @RequestHeader(value = "papVersion", defaultValue = "1.0") String papVersion,
                                         @RequestBody com.pap.uua.dto.UserDTO userDTO) {
        if(userDTO != null &&StringUtilss.isNotEmpty(userDTO.getUserName()) && StringUtilss.isNotEmpty(userDTO.getPassword())
            && StringUtilss.isNotEmpty(userDTO.getDomain()) && StringUtilss.isNotEmpty(userDTO.getAuthenticationType())) {
            if("b".equals(userDTO.getDomain()) && "password".equals(userDTO.getAuthenticationType())) {
                com.pap.rbacfeignapi.dto.UserLoginDTO userLoginDTO = new com.pap.rbacfeignapi.dto.UserLoginDTO();
                userLoginDTO.setUserLoginName(userDTO.getUserName());
                userLoginDTO.setUserPasswords(userDTO.getPassword());
                ResponseVO<UserInfoDTO> userInfoDTOResponseVO = userService.loginByLoginName(papVersion, userLoginDTO);
                if(StringUtilss.isNotEmpty(userInfoDTOResponseVO.getCode()) && "200".equals(userInfoDTOResponseVO.getCode())) {
                    // token 生成
                    JWTUserDTO jwtUserDTO = new JWTUserDTO();
                    BeanCopyUtilss.myCopyProperties(userInfoDTOResponseVO.getData(), jwtUserDTO);

                    String token = JWTTokenUtilss.create(jwtUserDTO, JWTConstants.SECRET, JWTConstants.VALIDITY_TIME_MS);

                    JWTTokenDTO jwtTokenDTO = new JWTTokenDTO();
                    jwtTokenDTO.setToken(token);
                    jwtTokenDTO.setUserId(userInfoDTOResponseVO.getData().getUserId());
                    jwtTokenDTO.setUserName(userInfoDTOResponseVO.getData().getUserName());
                    jwtTokenDTO.setPermissionCodeList(userInfoDTOResponseVO.getData().getPermissionCodeList());
                    jwtTokenDTO.setValidityTimeMs(JWTConstants.VALIDITY_TIME_MS);

                    return ResponseVO.successdata(jwtTokenDTO);
                } else {
                    return ResponseVO.validfail(userInfoDTOResponseVO.getMsg());
                }
            } else {
                return ResponseVO.validfail("不支持的登录方式!");
            }
        } else {
            return ResponseVO.validfail("数据不完整!");
        }
    }

    /**
     * blockHandler / blockHandlerClass: blockHandler 对应处理 BlockException 的函数名称，可选项。若未配置，则将 BlockException 直接抛出。
     * blockHandler 函数访问范围需要是 public，返回类型需要与原方法相匹配，参数类型需要和原方法相匹配并且最后加一个额外的参数，类型为 BlockException。
     * blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数，则可以指定 blockHandlerClass 为对应的类的 Class 对象，
     * 注意对应的函数必需为 static 函数，否则无法解析。
     * @param papToken
     * @param papVersion
     * @param userDTO
     * @param exception
     * @return
     */
    public static ResponseVO<JWTTokenDTO> handleTokenException(String papToken, String papVersion,
                                                          com.pap.uua.dto.UserDTO userDTO, BlockException exception) {
        return ResponseVO.forbidden("PAP 流量控制;限流");
    }

    /**
     * DegradeException 降级异常
     * The return type should match the origin method;
     * The parameter list should match the origin method， do not add an additional Throwable parameter
     * @return
     */
    public static ResponseVO<JWTTokenDTO> handleTokenFallback(String papToken, String papVersion,
                                                              com.pap.uua.dto.UserDTO userDTO) {
        return ResponseVO.forbidden("PAP 流量控制;降级");
    }

    /**
     * 校验 JWT
     * @param papToken
     * @return
     */
    @RequestMapping(value = "/checktoken", method = {RequestMethod.POST} )
    public ResponseVO<JWTUserDTO> checkToken(@RequestHeader(value = "papToken", defaultValue = "-1") String papToken) {
        try {
            JWTUserDTO jwtUserDTO = JWTTokenUtilss.parse(papToken, JWTConstants.SECRET);
            return ResponseVO.successdata(jwtUserDTO);
        } catch (Exception e) {
            logger.error("checkToken [{}]", e.getMessage());
            e.printStackTrace();
        }
        return ResponseVO.validfail("校验失败!");
    }

    /**
     *  刷新 JWT
     * @param papToken
     * @return
     */
    @RequestMapping(value = "/refreshtoken", method = {RequestMethod.POST} )
    public ResponseVO<JWTUserDTO> refreshToken(@RequestHeader(value = "papToken", defaultValue = "-1") String papToken) {
        try {
            JWTUserDTO jwtUserDTO = JWTTokenUtilss.parse(papToken, JWTConstants.SECRET);

            String token = JWTTokenUtilss.create(jwtUserDTO, JWTConstants.SECRET, JWTConstants.VALIDITY_TIME_MS);

            JWTTokenDTO jwtTokenDTO = new JWTTokenDTO();
            jwtTokenDTO.setToken(token);
            jwtTokenDTO.setValidityTimeMs(JWTConstants.VALIDITY_TIME_MS);

            return ResponseVO.successdata(jwtTokenDTO);
        } catch (Exception e) {
            logger.error("refreshToken [{}]", e.getMessage());
            e.printStackTrace();
        }
        return ResponseVO.validfail("刷新失败!");
    }

    @RequestMapping(value = "/getcurrtime", method = {RequestMethod.GET} )
    public ResponseVO<Long> getCurrTime() {
        return ResponseVO.successdata(System.currentTimeMillis());
    }

}
